package io.netty.test.main.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author LuoYu
 * @date 2018/11/02 9:27
 * <p>
 * Description:
 * 暴躁的NIO客户端
 */
public class CrazyNIOClient {

    public static void writeMsg(SocketChannel channel, String msg) throws IOException {
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        //向服务端发送消息
        buffer.put(("current time : " + System.currentTimeMillis()).getBytes());
        buffer.put("\n".getBytes());
        buffer.put(msg.getBytes());
        //读取模式
        buffer.flip();
        channel.write(buffer);

    }

    public static void start() {
        try (SocketChannel channel = SocketChannel.open()) {
            SocketAddress socketAddress = new InetSocketAddress("localhost", 8080);
            Selector selector = Selector.open();
            channel.configureBlocking(false);
            // channel连接服务端  失败将channel标记为可连接
            if (channel.connect(socketAddress)) {
                // 连接成功标记为可读（这些标记都是以服务端的角度）
                channel.register(selector, SelectionKey.OP_READ);
                // 写数据
                writeMsg(channel, "666666");
                channel.register(selector, SelectionKey.OP_WRITE);
            } else {
                // 连接失败标记为可连接
                channel.register(selector, SelectionKey.OP_CONNECT);
            }


            // 客户端也有selector
            // 通过select管理连接 避免connection refused
            for (; ; ) {
                selector.select(1000);
                Set<SelectionKey> keys = selector.selectedKeys();
                Iterator<SelectionKey> it = keys.iterator();
                SelectionKey key;
                while (it.hasNext()) {
                    key = it.next();
                    it.remove();
                    SocketChannel sc = (SocketChannel) key.channel();
                    if (key.isAcceptable()) {

                    } else if (key.isWritable()) {

                    } else if (key.isReadable()) {
                        ByteBuffer buffer = ByteBuffer.allocate(1024);
                        //从服务端读取消息
                        int readLenth = channel.read(buffer);
                                //读取模式
                        buffer.flip();
                        byte[] bytes = new byte[readLenth];
                        buffer.get(bytes);
                        System.out.println(new String(bytes, "UTF-8"));
                        buffer.clear();
                        key.interestOps(SelectionKey.OP_READ);
                    } else if (key.isConnectable()) {
                        // 由于非阻塞模式，connect只管发起连接请求，finishConnect()方法会阻塞到链接结束并返回是否成功
                        // 另外还有一个isConnectionPending()返回的是是否处于正在连接状态(还在三次握手中)
                        if (channel.finishConnect()) {
                       /* System.out.println("准备发送数据");
                        // 链接成功了可以做一些自己的处理
                        channel.write(charset.encode("I am Coming"));
                        // 处理完后必须吧OP_CONNECT关注去掉，改为关注OP_READ
                        key.interestOps(SelectionKey.OP_READ);*/
                            sc.register(selector, SelectionKey.OP_READ);
                            writeMsg(channel, "66666666");
                        } else {
                            //链接失败，进程推出或直接抛出IOException
                            System.exit(1);
                        }
                    }


                }
            }


        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        for (int i = 0;i < 1000 ; i++){
        new Thread(() ->{
            System.out.println(Thread.currentThread().getName());
            CrazyNIOClient.start();
        }

        ).start();
        }
    }
}

